package com.qwiki.classification;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;

import com.qwiki.dict.TextDictionary;

import org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;

import opennlp.tools.doccat.DoccatModel;
import opennlp.tools.doccat.DocumentCategorizerME;

public class Classifier {
  public static void main(String[] args) throws IOException {
    Logger.getRootLogger()
        .addAppender(new ConsoleAppender(new PatternLayout("%d{yyyy/MM/dd HH:mm:ss.SSS} %p [%c{1}] [%x] %m%n")));


    Options options = new Options();

    Option option = OptionBuilder.create("model");
    option.setRequired(true);
    option.setArgs(1);
    option.setDescription("the output of textify");
    options.addOption(option);

    CommandLineParser cliParser = new BasicParser();

    String model = null;
    try {
      CommandLine cli = cliParser.parse(options, args);
      model = cli.getOptionValue("model");
    } catch (Exception e) {
      e.printStackTrace();
      System.exit(0);
    }

    InputStream is = Files.newInputStream((new File(model)).toPath());
    DoccatModel m = new DoccatModel(is);
    String consoleInput = "";
    String inputText = "";
    LineNumberReader reader = new LineNumberReader(new InputStreamReader(System.in));
    while (true) {
      consoleInput = reader.readLine();
      while (!consoleInput.equals(".")) {
        inputText += consoleInput + " ";
        consoleInput = reader.readLine();
      }
      if (inputText.length() > 1 && !inputText.equals("quit")) {
        DocumentCategorizerME myCategorizer = new DocumentCategorizerME(m);
        inputText = inputText.toLowerCase().replaceAll("[^a-z]", " ");

        String processed = TextDictionary.dict.filter(inputText);
        System.out.println("======= de-space\n");
        System.out.println(inputText);
        System.out.println("=======processed: \n" + processed + "\n=======");
        String last = processed;
        processed = processed.replaceAll("  ", " ");
        while (!last.equals(processed)) {
          last = processed;
          processed = processed.replaceAll("  ", " ");
        }
        double[] outcomes = myCategorizer.categorize(processed);
        System.out.println();
        String[] topN = getTopN(outcomes, 30, myCategorizer);
        System.out.println(Arrays.toString(topN) + "\n");
        inputText = "";
      } else if (inputText.equals("quit")) System.exit(0);
    }
  }

  private static String[] getTopN(final double[] outcomes, int N, DocumentCategorizerME cat) {
    Comparator<Integer> qpc = new Comparator<Integer>() {

      @Override
      public int compare(Integer o1, Integer o2) {
        double s1 = outcomes[o1];
        double s2 = outcomes[o2];
        if (s1 < s2) return -1;
        if (s1 > s2) return 1;
        return 0;
      }
    };
    PriorityQueue<Integer> pq = new PriorityQueue<Integer>(N, qpc);
    for (int i = 0; i < outcomes.length; i++) {
      if (pq.size() > N) {
        int top = pq.peek();
        if (outcomes[i] > outcomes[top])
          pq.add(i);
      } else {
        pq.add(i);
      }
    }
    String[] topN = new String[N];
    int n = Math.max(0, pq.size() - N);
    for (int i = 0; i < n; i++) {
      pq.poll();
    }
    n = pq.size();
    for (int i = 0; i < n; i++) {
      int index = pq.poll();
      topN[n - 1 - i] = cat.getCategory(index);
      System.out.println(topN[n - 1 - i] + "\t " + outcomes[index]);
    }
    return topN;
  }
}
